package com.hsd.znsh.service.impl;

import com.hsd.znsh.controller.manager.ManagerHostController;
import com.hsd.znsh.converter.OpinionConverter;
import com.hsd.znsh.converter.UserConverter;
import com.hsd.znsh.entity.*;
import com.hsd.znsh.enums.*;
import com.hsd.znsh.exception.ZnshException;
import com.hsd.znsh.pojo.input.APPRegisterUser;
import com.hsd.znsh.pojo.input.ForgetPasswordPhone;
import com.hsd.znsh.pojo.input.PCRegisterUser;
import com.hsd.znsh.pojo.input.UserInfoInput;
import com.hsd.znsh.pojo.output.OpinionVO;
import com.hsd.znsh.pojo.output.UserInfoVO;
import com.hsd.znsh.pojo.output.UserVO;
import com.hsd.znsh.pojo.query.OpinionQuery;
import com.hsd.znsh.pojo.query.UserQuery;
import com.hsd.znsh.properties.SecurityProperties;
import com.hsd.znsh.repository.*;
import com.hsd.znsh.service.UserService;
import com.hsd.znsh.utils.BeanUtil;
import com.hsd.znsh.utils.HqlUtil;
import com.hsd.znsh.utils.SecurityUtil;
import com.hsd.znsh.utils.ValidatorUtil;
import com.lly835.bestpay.utils.RandomUtil;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;

/*
 * @auther: wangjiacai
 *
 * @create: 2018-04-23 11:51:45
 */
@Service
@Transactional
public class UserServiceImpl extends BaseServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private UserRoleRepository userRoleRepository;

    @Autowired
    private UserMonitorRepository userMonitorRepository;

    @Autowired
    private UserSensorGroupRepository userSensorGroupRepository;

    @Autowired
    private MonitorRepository monitorRepository;

    @Autowired
    private SensorGroupRepository sensorGroupRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private OpinionRepository opinionRepository;

    @Autowired
    private HostManagerRepository hostManagerRepository;

    @Override
    public List<Map> getManagerUserRoleList() {
        List<Map> list=new ArrayList<>();
        list.add(getUserRoleMap(UserRoleEnum.GENERAL));
        list.add(getUserRoleMap(UserRoleEnum.VIP));
        list.add(getUserRoleMap(UserRoleEnum.APP_MANAGER));
        list.add(getUserRoleMap(UserRoleEnum.PC_MANAGER));
        if(SecurityUtil.hasRole("ROLE_ROOT")){
            list.add(getUserRoleMap(UserRoleEnum.BACKGROUND_MANAGER));
            list.add(getUserRoleMap(UserRoleEnum.ROOT));
        }
        return list;
    }


    private Map getUserRoleMap(UserRoleEnum userRoleEnum){
        Map<String,Object> map=new HashMap();
        map.put("userType",userRoleEnum.getCode());
        map.put("role",userRoleEnum.getMessage());
        return  map;
    }

    @Override
    public long getUserListTotalPages(UserQuery userQuery,Integer userId) {
        if(userId==null) initUserQuery(userQuery);
        else userQuery.setCreateUserId(userId);
        return this.count(HqlUtil.getCountHql(userQuery),userQuery);
    }

    @Override
    public List<UserVO> getUserList(Pageable pageable, UserQuery userQuery,Integer userId) {
        if(userId==null) initUserQuery(userQuery);
        else userQuery.setCreateUserId(userId);
        List<User> list= this.find(HqlUtil.getQueryHql(userQuery),userQuery,pageable);
        return UserConverter.convertToUserVOList(list,userRepository);
    }

    @Override
    public List<UserVO> getUserList(UserQuery userQuery) {
        initUserQuery(userQuery);
        List<User> list= this.find(HqlUtil.getQueryHql(userQuery),userQuery);
        return UserConverter.convertToUserVOList(list,userRepository);
    }

    private void initUserQuery(UserQuery userQuery) {
        if (!StringUtils.isEmpty(userQuery.getCreateUsername())) {
            List<Integer> userIds = userRepository.findIdListByUsernameLike(userQuery.getUsername());
            if (userIds == null) userIds = new ArrayList<>();
            userQuery.setCreateUserIds(userIds);
        }
    }

    @Override
    public UserInfoVO getUserInfo(Integer id) {
        User user=userRepository.findOne(id);
        UserInfoVO userInfoVO=UserConverter.convertToUserInfoVO(user,userRepository);

        List<Integer> monitorIds=userMonitorRepository.findMonitorIdListByUserId(id);
        List<Monitor> monitors=monitorRepository.findByIdIn(monitorIds);
        userInfoVO.setMonitors(monitors);

        List<Integer> sensorGroupIds=userSensorGroupRepository.findSensorGroupIdListByUserId(id);
        List<SensorGroup> sensorGroups=sensorGroupRepository.findByIdIn(sensorGroupIds);
        userInfoVO.setSensorGroups(sensorGroups);
        return userInfoVO;
    }

    @Override
    public User addUserInfo(UserInfoInput userInfoInput) {
        validAddUserInfo(userInfoInput);
        if(SecurityUtil.hasRole("ROLE_BACKGROUND_MANAGER")){
            userInfoInput.setCreateUserId(SecurityUtil.getUserId());
        }else{
            if(userInfoInput.getCreateUserId()==null){
                userInfoInput.setCreateUserId(SecurityUtil.getUserId());
            }
        }
        User target=new User();
        BeanUtil.copyPropertiesIgnoreNull(userInfoInput,target);
        target.setPassword(passwordEncoder.encode(target.getPhone()));
        userRepository.save(target);
        distributionSensorGroup(userInfoInput.getSensorGroups(),userInfoInput.getId());
        distributionMonitor(userInfoInput.getMonitors(),userInfoInput.getId());

        UserRole userRole=new UserRole();
        userRole.setRoleId(target.getUserType());
        userRole.setUserId(target.getId());
        userRoleRepository.save(userRole);
        return target;
    }

    private void validAddUserInfo(UserInfoInput userInfoInput){
        if(userRepository.findByUsername(userInfoInput.getUsername())!=null){
            throw new ZnshException(ResultEnum.USERNAME_EXITS);
        }
        if(userRepository.findByPhone(userInfoInput.getPhone())!=null){
            throw new ZnshException(ResultEnum.PHONE_EXITS);
        }
    }

    @Override
    public void updateUserInfo(UserInfoInput userInfoInput) {
        validUpdateUserInfo(userInfoInput);
        if(SecurityUtil.hasRole("ROLE_BACKGROUND_MANAGER")){
            userInfoInput.setCreateUserId(SecurityUtil.getUserId());
        }else{
            if(userInfoInput.getCreateUserId()==null){
                userInfoInput.setCreateUserId(SecurityUtil.getUserId());
            }
        }
        User target=userRepository.findOne(userInfoInput.getId());
        BeanUtil.copyPropertiesIgnoreNull(userInfoInput,target);
        userRepository.save(target);
        userSensorGroupRepository.deleteByUserId(userInfoInput.getId());
        userMonitorRepository.deleteByUserId(userInfoInput.getId());
        distributionSensorGroup(userInfoInput.getSensorGroups(),userInfoInput.getId());
        distributionMonitor(userInfoInput.getMonitors(),userInfoInput.getId());
        UserRole userRole=userRoleRepository.findByUserId(target.getId());
        userRole.setRoleId(target.getUserType());
        userRoleRepository.save(userRole);
    }

    private void validUpdateUserInfo(UserInfoInput userInfoInput){
        User user=userRepository.findOne(userInfoInput.getId());
        if(!userInfoInput.getUsername().equals(user.getUsername())){
            if(userRepository.findByUsername(userInfoInput.getUsername())!=null){
                throw new ZnshException(ResultEnum.USERNAME_EXITS);
            }
        }
        if(!userInfoInput.getPhone().equals(user.getPhone())){
            if(userRepository.findByPhone(userInfoInput.getPhone())!=null){
                throw new ZnshException(ResultEnum.PHONE_EXITS);
            }
        }
    }

    private void distributionSensorGroup(String sensorGroups,Integer userId){
        String[] sensorGroupIds=sensorGroups.split(",");
        for(String s:sensorGroupIds){
            if(s.trim().equals("")) continue;
            UserSensorGroup userSensorGroup=new UserSensorGroup();
            userSensorGroup.setUserId(userId);
            userSensorGroup.setSensorGroupId(Integer.parseInt(s));
            userSensorGroupRepository.save(userSensorGroup);
        }
    }

    private void distributionMonitor(String monitors,Integer userId){
        String[] monitorIds=monitors.split(",");
        for(String s:monitorIds){
            if(s.trim().equals("")) continue;
            UserMonitor userMonitor=new UserMonitor();
            userMonitor.setUserId(userId);
            userMonitor.setMonitorId(Integer.parseInt(s));
            userMonitorRepository.save(userMonitor);
        }
    }


    @Override
    public void deleteUser(Integer userId) {
        User user=userRepository.findOne(userId);
        user.setDeleted(DeletedStatusEnum.DELETED.getCode());
        userRepository.save(user);
    }

    @Override
    public User registerPCUser(PCRegisterUser pcRegisterUser) {
        validRegisterPCUser(pcRegisterUser);
        User user=new User();
        user.setPhone(pcRegisterUser.getPhone());
        user.setPassword(passwordEncoder.encode(pcRegisterUser.getPassword()));
        user.setUsername(pcRegisterUser.getPhone());
        user.setUserType(UserRoleEnum.GENERAL.getCode());
        user=userRepository.save(user);
        distributionSensorGroup(securityProperties.getSensorGroups(),user.getId());
        distributionMonitor(securityProperties.getMonitors(),user.getId());
        return user;
    }

    private void validRegisterPCUser(PCRegisterUser pcRegisterUser){
        if(!pcRegisterUser.getPassword().equals(pcRegisterUser.getConfirmPassword())){
            throw new ZnshException(ResultEnum.PASSWORD_CONFIRMPASSWORD_NOT_SAME);
        }
        if(userRepository.findByPhone(pcRegisterUser.getPhone())!=null){
            throw new ZnshException(ResultEnum.PHONE_EXITS);
        }
    }

    @Override
    public User registerAPPUser(APPRegisterUser appRegisterUser) {
        validRegisterAPPUser(appRegisterUser);
        User user=new User();
        user.setPhone(appRegisterUser.getPhone());
        user.setPassword(passwordEncoder.encode(appRegisterUser.getPassword()));
        user.setUsername(appRegisterUser.getUsername());
        user.setUserType(UserRoleEnum.APP_MANAGER.getCode());
        return userRepository.save(user);
    }

    private void validRegisterAPPUser(APPRegisterUser appRegisterUser){
        if(!appRegisterUser.getPassword().equals(appRegisterUser.getConfirmPassword())){
            throw new ZnshException(ResultEnum.PASSWORD_CONFIRMPASSWORD_NOT_SAME);
        }
        if(userRepository.findByUsername(appRegisterUser.getUsername())!=null){
            throw new ZnshException(ResultEnum.USERNAME_EXITS);
        }
    }

    @Override
    public Opinion feedback(User user, Opinion opinion) {
        opinion.setCreateDateTime(new Date());
        opinion.setUserId(user.getId());
        return opinionRepository.save(opinion);
    }

    @Override
    public long getOpinionListTotalPages(OpinionQuery opinionQuery) {
        return this.count(HqlUtil.getCountHql(opinionQuery),opinionQuery);
    }

    @Override
    public List<OpinionVO> getOpinionList(Pageable pageable, OpinionQuery opinionQuery) {
        List<Opinion> list=this.find(HqlUtil.getQueryHql(opinionQuery),opinionQuery,pageable);
        return OpinionConverter.converterToOpinionVOList(list,userRepository);
    }

    @Override
    public OpinionVO getOpinionInfo(Integer id) {
        Opinion opinion=opinionRepository.findOne(id);
        return OpinionConverter.converterToOpinionVO(opinion,userRepository);
    }

    @Override
    public void deletedOpinion(Integer id) {
        opinionRepository.delete(id);
    }

    @Override
    public User forgetPassword(ForgetPasswordPhone forgetPasswordPhone) {
        User user=userRepository.findByPhoneAndDeleted(forgetPasswordPhone.getPhone(),DeletedStatusEnum.NOT_DELETED.getCode());
        if(user==null) throw new ZnshException(ResultEnum.PHONE_NOT_EXITS);
        user.setPassword(passwordEncoder.encode(forgetPasswordPhone.getPassword()));
        return userRepository.save(user);
    }

    @Override
    public void assignHost(String managerName, String ids) {
        User user=userRepository.findByUsername(managerName);
        hostManagerRepository.deleteBySecondManagerId(user.getId());
        for(String id:ids.split(",")){
            if(StringUtils.isEmpty(id)) continue;
            HostManager hostManager=new HostManager();
            hostManager.setSecondManagerId(user.getId());
            hostManager.setHostId(Integer.parseInt(id));
            hostManagerRepository.save(hostManager);
        }
    }

    @Override
    public User findAppUserByUsername(String username,String password) {
        User user= userRepository.findByUsernameAndDeleted(username,DeletedStatusEnum.NOT_DELETED.getCode());
        if(user.getUserType()!=UserRoleEnum.APP_MANAGER.getCode()){
            throw new ZnshException(ResultEnum.USERNAME_NOT_EXITS);
        }
        if(!passwordEncoder.matches(password,user.getPassword())){
            throw new ZnshException(ResultEnum.USERNAME_PASSWORD_ERROR);
        }
        return user;
    }
}
